home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 1 / Gold Medal Software Volume 1 (Gold Medal) (1994).iso / graphics / povsrc20.arj / MACHINE / UNIX / XWIN.C < prev    next >
C/C++ Source or Header  |  1993-08-06  |  16KB  |  496 lines

  1.  
  2. /* From: kelvin@autodesk.com (John Walker)
  3.  * Message-Id: <9206091233.AA22915@throop>
  4.  * To: 73767.1244@uunet.uu.net
  5.  * Subject: Extensions to XWIN.C module of POV-Ray
  6.  
  7.  * Attached is a modified version of the XWIN.C module included in the
  8.  * BETA 0.5 distribution of POV-Ray.  While the display is still dithered for
  9.  * a monochrome screen (I, too, have only a monochrome monitor on my X
  10.  * machine), it now uses the Floyd-Steinberg error diffusion algorithm rather
  11.  * than a fixed 8x8 dithering matrix, which results in *much* better looking
  12.  * images.  There is one slight drawback to this algorithm; it requires that
  13.  * you buffer an entire line of pixels before displaying them so the image
  14.  * now appears line-by-line rather that dot-by-dot.  I don't find this
  15.  * objectionable, and it does concentrate the display update context switches
  16.  * into one burst rather than a steady drone.
  17.  
  18.  * This code also includes optional gamma correction, which you can enable
  19.  * by defining the tag Gamma to the desired floating point value.  If Gamma is
  20.  * undefined (as in the attached code), the gamma correction is entirely
  21.  * disabled.
  22.  
  23.  * Thank you all for creating such a wonderful tool as POV-Ray.  I hope this
  24.  * contribution proves useful.
  25.  
  26.  */
  27. /*------------------------------------ Cut here ------------------------- xwin.c */
  28. /****************************************************************************
  29. *                xwindows.c
  30. *
  31. *  This module implements X-windows specific routines.
  32. *
  33. *  from Persistence of Vision Raytracer
  34. *  Copyright 1993 Persistence of Vision Team
  35. *---------------------------------------------------------------------------
  36. *  NOTICE: This source code file is provided so that users may experiment
  37. *  with enhancements to POV-Ray and to port the software to platforms other 
  38. *  than those supported by the POV-Ray Team.  There are strict rules under
  39. *  which you are permitted to use this file.  The rules are in the file
  40. *  named POVLEGAL.DOC which should be distributed with this file. If 
  41. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  42. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  43. *  Forum.  The latest version of POV-Ray may be found there as well.
  44. *
  45. * This program is based on the popular DKB raytracer version 2.12.
  46. * DKBTrace was originally written by David K. Buck.
  47. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  48. *
  49. *****************************************************************************/
  50.  
  51.  
  52.   /*
  53.         Here are some routines I wrote which implement +d option on
  54.         unix computers running X-windows. For now, only black
  55.         and white output is supported. If I get access to a computer
  56.         with a color monitor, I'll probably add support for colors to
  57.         my routines.
  58.  
  59.         In future I'll probably add some more dithering methods.
  60.         I have tested these routines on SUN 3 and SUN 4. I'm using
  61.         the tvtwm window manager.
  62.  
  63.         If you have some suggestions to my source code or if you change
  64.         anything, please let me know. I can be reached at the following
  65.         address: Marek Rzewuski, Avstikkeren 11, 1156 Oslo 11, Norway or
  66.         marekr@ifi.uio.no on Internet.
  67.  
  68.                                     * * *
  69.  
  70.         On  9th May 1992, I replaced the original 8x8 dithering matrix
  71.         in this module with Floyd-Steinberg error diffusion mapping of
  72.         the  YIQ-derived  grey  scale  into  a monochrome bitmap.  The
  73.         Floyd-Steinberg code was based on the algorithm  used  in  the
  74.         "pgmtopbm" module of Jef Poskanzer's raster toolkit (PBMPLUS).
  75.  
  76.         In addition, I added optional gamma correction (with a default
  77.         factor  of  0.5),  to darken the picture somewhat and increase
  78.         the level  of  perceived  detail.   The  gamma  correction  is
  79.         disabled  in the standard version, but you can turn it back on
  80.         by uncommenting the  declaration  of  Gamma  if  you  find  it
  81.         improves the quality of the pictures you're making.
  82.                 -- John Walker
  83.                    Autodesk Neuchatel
  84.                    Internet: kelvin@Autodesk.com
  85.  
  86. */
  87.  
  88. #include <stdio.h>
  89. #include <X11/Xlib.h>           /* some Xlib stuff */
  90. #include <X11/Xutil.h>
  91. #include "theIcon"
  92.  
  93. #include "frame.h"
  94. #include "povproto.h"
  95.  
  96. #define         BORDER_WIDTH    2
  97. #define EV_MASK (ButtonPressMask | \
  98.                  KeyPressMask    | \
  99.                  ExposureMask    | \
  100.                  StructureNotifyMask)
  101.  
  102. Display         *theDisplay;
  103. int             theScreen;
  104. int             theDepth;
  105. unsigned long   theBlackPixel;
  106. unsigned long   theWhitePixel;
  107. XEvent          theEvent;
  108. Window          theWindow, openWindow();
  109. GC              theGC;
  110. unsigned char   *bitmap;        /* pointer to our picture bitmap */
  111. unsigned char   *bitmapPos;     /* position to the last drawn pixel in our bitm
  112. ap */
  113.  
  114.  
  115. /* global POV-Ray variables */
  116.  
  117. extern FRAME Frame;
  118. extern unsigned int Options;
  119. extern char DisplayFormat;
  120. extern int First_Line;
  121.  
  122. enum pixval { BLACK, WHITE };
  123.  
  124. /* #define Gamma      0.5 */          /* Screen gamma correction factor */
  125. #define Fthreshold 0.5
  126.  
  127. static unsigned char *scrline;
  128. #ifdef Gamma
  129. static unsigned char gammamap[256];
  130. #endif
  131. static enum pixval *pixrow;
  132. static long *thiserr, *nexterr, *temperr;
  133. static long threshval, sum;
  134. static int ncols;                     /* Screen width */
  135. #define FS_SCALE 1024
  136. #define HALF_FS_SCALE 512
  137. static int fs_direction;
  138.  
  139. void unix_init_POVRAY PARAMS ((void))
  140. {
  141. }
  142.  
  143.  
  144. /* Sets up a connection to the X server and stores informations about the envir
  145. oment */
  146.  
  147. initX()
  148. {
  149.   theDisplay = XOpenDisplay(NULL);
  150.   if (theDisplay == NULL) {
  151.     fprintf(stderr,"ERROR: Cannot establish a connection to the X server %s\n",
  152.             XDisplayName(NULL));
  153.     exit(1);
  154.   }
  155.   theScreen = DefaultScreen(theDisplay);
  156.   theDepth  = DefaultDepth(theDisplay, theScreen);
  157.   theWhitePixel = WhitePixel(theDisplay, theScreen);
  158.   theBlackPixel = BlackPixel(theDisplay, theScreen);
  159. }
  160.  
  161. /* This procedure will do the following things:
  162.    1)   Set up attributes desired for the window
  163.    2)   Set up an icon to our window.
  164.    3)   Send hints to the window manager.
  165.    4)   Open a window on the display
  166.    5)   Tell the X to place the window on the screen
  167.    6)   Flush out all the queued up X requests to the X server */
  168.  
  169. Window openWindow(x,y,width,height,flag,theNewGC)
  170. int     x,y;
  171. int     width,height;
  172. int     flag;
  173. GC      *theNewGC;
  174. {
  175.   XSetWindowAttributes  theWindowAttributes;
  176.   XSizeHints            theSizeHints;
  177.   unsigned      long    theWindowMask;
  178.   Window                theNewWindow;
  179.   Pixmap                theIconPixmap;
  180.   XWMHints              theWMHints;
  181.  
  182.  
  183.   /* Set up some attributes for the window. Override_redirect tells
  184.      the window manager to deal width the window or leave it alone */
  185.  
  186.   theWindowAttributes.border_pixel      = theBlackPixel;
  187.   theWindowAttributes.background_pixel  = theWhitePixel;
  188.   theWindowAttributes.override_redirect = False;
  189.   theWindowMask = CWBackPixel | CWBorderPixel | CWOverrideRedirect;
  190.  
  191.   /* Now, open out window */
  192.  
  193.   theNewWindow = XCreateWindow(theDisplay,
  194.                                RootWindow(theDisplay,theScreen),
  195.                                x,y,
  196.                                width, height,
  197.                                BORDER_WIDTH,
  198.                                theDepth,
  199.                                InputOutput,
  200.                                CopyFromParent,
  201.                                theWindowMask,
  202.                                &theWindowAttributes);
  203.  
  204.   /* Create one iconbitmap */
  205.  
  206.   theIconPixmap = XCreateBitmapFromData(theDisplay,
  207.                                         theNewWindow,
  208.                                         theIcon_bits,
  209.                                         theIcon_width,
  210.                                         theIcon_height);
  211.  
  212.   /* Now tell the window manager where on screen we should place our
  213.      window. */
  214.  
  215.   theWMHints.icon_pixmap        = theIconPixmap;
  216.   theWMHints.initial_state      = NormalState;          /* we don't want an ico
  217. nized window when it's created */
  218.   theWMHints.flags              = IconPixmapHint | StateHint;
  219.  
  220.   XSetWMHints(theDisplay,theNewWindow,&theWMHints);
  221.  
  222.   theSizeHints.flags            = PPosition | PSize;
  223.   theSizeHints.x                = x;
  224.   theSizeHints.y                = y;
  225.   theSizeHints.width            = width;
  226.   theSizeHints.height           = height;
  227.  /* theSizeHints.min_width      = width;
  228.   theSizeHints.min_height       = height;
  229.   theSizeHints.max_width        = width;
  230.   theSizeHints.max_height       = height; */
  231.  
  232.   XSetNormalHints(theDisplay,theNewWindow,&theSizeHints);
  233.  
  234.  
  235.   if (createGC(theNewWindow, theNewGC) == 0) {
  236.     XDestroyWindow(theDisplay, theNewWindow);
  237.     return((Window) 0);
  238.   }
  239.  
  240.   /* Make a name for our window */
  241.  
  242.   XStoreName(theDisplay, theNewWindow, "Persistence Of Vision Raytracer\0");
  243.  
  244.   /* Now, could we please see the window on the screen?
  245.      Until now, we have dealt with a window which has been created
  246.      but not appeared on the screen. Maping the window places it visibly
  247.  
  248.      on the screen */
  249.  
  250.   XMapWindow(theDisplay,theNewWindow);
  251.   XFlush(theDisplay);
  252.   return(theNewWindow);
  253. }
  254.  
  255. refreshWindow(theExposedWindow)
  256. Window  theExposedWindow;
  257. {
  258.   int   i, x, y;
  259.   unsigned char *dummy;
  260.   dummy = bitmap;
  261.   i = 0; x= 0; y = First_Line;
  262.   while (dummy < bitmapPos) {
  263.     if (*dummy)
  264.       XDrawPoint(theDisplay, theWindow, theGC,x,y);
  265.     if (x == Frame.Screen_Width) {
  266.       x = 0;
  267.       y++;
  268.     } else {
  269.       dummy++;
  270.       x++;
  271.       i++;
  272.     }
  273.   }
  274.   XFlush(theDisplay);
  275. }
  276.  
  277. /* Creates a new graphics context */
  278.  
  279. createGC(theNewWindow, theNewGC)
  280. Window  theNewWindow;
  281. GC      *theNewGC;
  282. {
  283.   XGCValues theGCValues;
  284.   *theNewGC = XCreateGC(theDisplay,
  285.                         theNewWindow,
  286.                         (unsigned long) 0,
  287.                         &theGCValues);
  288.  
  289.   if (*theNewGC == 0) {
  290.     return(0); /*error*/
  291.   } else { /* set foreground and background defaults for the new GC */
  292.     XSetForeground(theDisplay,
  293.                    *theNewGC,
  294.                    theBlackPixel);
  295.  
  296.     XSetBackground(theDisplay,
  297.                   *theNewGC,
  298.                   theWhitePixel);
  299.  
  300.     return(1); /* OK */
  301.   }
  302. }
  303.  
  304. initEvents(theWindow)
  305. Window theWindow;
  306. {
  307.   XSelectInput(theDisplay,
  308.                theWindow,
  309.                EV_MASK);
  310. }
  311.  
  312. void display_finished ()
  313. {
  314. }
  315.  
  316. void display_init ()
  317. {
  318.   int i;
  319.   int cols;
  320.  
  321.   /* Allocate error propagation vectors for Floyd-Steinberg algorithm. */
  322.  
  323.   ncols = Frame.Screen_Width;
  324.   cols = ncols + 2;
  325.   scrline = (unsigned char *) malloc(ncols * sizeof(unsigned char));
  326.   pixrow = (enum pixval *) malloc(ncols * sizeof(enum pixval));
  327.   thiserr = (long *) malloc(cols * sizeof(long));
  328.   nexterr = (long *) malloc(cols * sizeof(long));
  329.   if (scrline == NULL || pixrow == NULL ||
  330.       thiserr == NULL || nexterr == NULL) {
  331.     printf("XWIN error: Failed to allocate Floyd-Steinberg error vectors.\n");
  332.     exit(0);
  333.   }
  334.   srandom((int) (time(NULL) ^ getpid()));
  335.   /* (Random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
  336.   for (i = 0; i < cols; i++) {
  337.       thiserr[i] = (random() % FS_SCALE - HALF_FS_SCALE) / 4;
  338.   }
  339.   fs_direction = 1;
  340.   threshval = Fthreshold * FS_SCALE;
  341.  
  342.   /* Initialise gamma correction table. */
  343.  
  344. #ifdef Gamma
  345.   for (i = 0; i < 256; i++) {
  346.     int gc = 255.0 * pow((((double) i) / 255.0), (1.0 / Gamma)) + 0.5;
  347.  
  348.     gammamap[i] = (gc > 255) ? 255 : gc;
  349.   }
  350. #endif
  351.  
  352.   /* Set some room for a bitmap for our picture.  I've got to
  353.      "remember" the whole picture because of resizing of the window,
  354.      overlapping etc.  Then I've got to refresh the picture.  This
  355.      should be easy to convert to an "color version" in future */
  356.  
  357.   bitmap = (unsigned char *) malloc(sizeof(unsigned char) *
  358.                                  (Frame.Screen_Width * Frame.Screen_Height));
  359.   bitmapPos = bitmap;
  360.   if (bitmap == NULL) {
  361.     printf("XWIN error: Can not allocate the buffer..\n");
  362.     exit(0);
  363.   }
  364.  
  365.   for (i = 0; i < (Frame.Screen_Width*Frame.Screen_Height); i++) {
  366.     *bitmapPos++ = 0;
  367.   }
  368.   bitmapPos = bitmap;
  369.   initX();
  370.   theWindow = openWindow(0,0,Frame.Screen_Width,Frame.Screen_Height,0,&theGC);
  371.   initEvents(theWindow);
  372.   XFlush(theDisplay);
  373. #ifdef NEEDED
  374.   /* On my Sun SPARCStation 2 running OpenWindows 3.0, this XNextEvent call
  375.      sometimes makes the window go to sleep until some event is artificially
  376.      generated for it (for example, by clicking the mouse in it).  I removed
  377.      the call and everything seems to work just fine.  -- JW */
  378.   XNextEvent(theDisplay,&theEvent);
  379.   XFlush(theDisplay);
  380. #endif
  381. } /* end of display initialisation */
  382.  
  383. void display_close ()
  384. {
  385.   sleep(10);                            /* an simple delay. 10 seconds. */
  386.   XDestroyWindow(theDisplay,theWindow);
  387.   XFlush(theDisplay);
  388.   XCloseDisplay(theDisplay);
  389.   free(bitmap);
  390. }
  391.  
  392. void display_plot (x, y, Red, Green, Blue)
  393. int x, y;
  394. unsigned char Red, Green, Blue;
  395. {
  396.   int                   numEvents;
  397.   /* lets find if there are some events waiting for us */
  398.  
  399.   numEvents = XPending(theDisplay);
  400.   if (numEvents > 0) {                  /* now deal with the events.. */
  401.     XNextEvent(theDisplay,&theEvent);
  402.  
  403.     switch (theEvent.type) {
  404.     case Expose:
  405.       /*printf("Window is exposed.\n");*/
  406.       refreshWindow(theEvent.xany.window);
  407.       break;
  408.  
  409.     case MapNotify:
  410.       /*printf("The window is mapped.\n");*/
  411.       refreshWindow(theEvent.xany.window);
  412.       break;
  413.  
  414.     case ButtonPress:
  415.       /*printf("A mouse button was pressed.\n");*/
  416.       break;
  417.  
  418.     case ConfigureNotify:
  419.       /*printf("The window configuration has been changed\n");*/
  420.       refreshWindow(theEvent.xany.window);
  421.       break;
  422.     }
  423.   }
  424.   scrline[x] =
  425. #ifdef Gamma
  426.                gammamap[
  427. #endif
  428.                         (int) (0.299 * Red + 0.587 * Green  + 0.114 * Blue)
  429. #ifdef Gamma
  430.                        ]
  431. #endif
  432.                         ;
  433.  
  434.   if (x >= (ncols - 1)) {
  435.     int col, limitcol;
  436.     unsigned char *pixelp;            /* Grey scale pixel pointer */
  437.     enum pixval *bitmapp;             /* Monochrome bitmap pointer */
  438.  
  439.     for (col = 0; col < ncols + 2; ++col) {
  440.         nexterr[col] = 0;
  441.     }
  442.     if (fs_direction) {
  443.         col = 0;
  444.         limitcol = ncols;
  445.         pixelp = scrline;
  446.         bitmapp = pixrow;
  447.     } else {
  448.         col = ncols - 1;
  449.         limitcol = -1;
  450.         pixelp = &(scrline[col]);
  451.         bitmapp = &(pixrow[col]);
  452.     }
  453.     do {
  454.         sum = ((long) *pixelp * FS_SCALE) / 255 + thiserr[col + 1];
  455.         if (sum >= threshval) {
  456.             *bitmapp = WHITE;
  457.             sum = sum - threshval - HALF_FS_SCALE;
  458.         } else {
  459.             *bitmapp = BLACK;
  460.         }
  461.  
  462.         if (fs_direction) {
  463.             thiserr[col + 2] += (sum * 7) / 16;
  464.             nexterr[col    ] += (sum * 3) / 16;
  465.             nexterr[col + 1] += (sum * 5) / 16;
  466.             nexterr[col + 2] += (sum    ) / 16;
  467.  
  468.             ++col;
  469.             ++pixelp;
  470.             ++bitmapp;
  471.         } else {
  472.             thiserr[col    ] += (sum * 7) / 16;
  473.             nexterr[col + 2] += (sum * 3) / 16;
  474.             nexterr[col + 1] += (sum * 5) / 16;
  475.             nexterr[col    ] += (sum    ) / 16;
  476.  
  477.             --col;
  478.             --pixelp;
  479.             --bitmapp;
  480.         }
  481.     } while (col != limitcol);
  482.     temperr = thiserr;                /* Swap error vectors */
  483.     thiserr = nexterr;
  484.     nexterr = temperr;
  485.     fs_direction = ! fs_direction;
  486.  
  487.     for (col = 0; col < ncols; col++) {
  488.       *bitmapPos++ = !pixrow[col];
  489.       if (!pixrow[col]) {
  490.         XDrawPoint(theDisplay, theWindow, theGC, col, y);
  491.       }
  492.     }
  493.   }
  494.   /*XFlush(theDisplay); Let's be nice to the network, OK? */
  495. }
  496.